using System;
using System.Collections.Generic;
using System.Linq;
using FireStarter.Base;
using Firestarter.DB.Schema.BO;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.Util;

namespace Firestarter.DB_DomainModel.Logic
{
    public class DBToDMObjectIdentityImporter : IDBToDMObjectIdentityImporter
    {
        public DMObjectIdentity Import(DMClass dmClass, DBPrimaryKey dbPrimaryKey, out IList<string> errorMessages)
        {
            errorMessages = new List<string>(4);
            if (dmClass == null) throw new ArgumentNullException("dmClass");
            if (dbPrimaryKey == null) throw new ArgumentNullException("dbPrimaryKey");

            var objectIdentity = GetMappedObjectIdentity(dmClass, dbPrimaryKey);

            foreach (DMProperty property in GetBusinessObjectArray(objectIdentity.Properties))
            {
                if (!dbPrimaryKey.PrimaryKeyColumns.Exists(MatchColumn(property)))
                {
                    objectIdentity.Properties.Remove(property);
                }
            }
            foreach (DBPrimaryKeyColumn pkColumn in GetBusinessObjectArray(dbPrimaryKey.PrimaryKeyColumns))
            {
                DMProperty property = pkColumn.Column.FindBOProperty(dmClass);
                if (property == null && !ApprovedDelete(pkColumn))
                {
                    AddErrorMessage(dmClass, pkColumn, errorMessages);
                    continue;
                }
                if (ApprovedDelete(pkColumn))
                {
                    pkColumn.MarkForDelete();
                    if (property != null) objectIdentity.Properties.Remove(property);
                }
                else
                {
                    objectIdentity.Properties.Add(property);
                }
                pkColumn.PendingChangeType = ChangeType.None;
            }
            return objectIdentity;
        }

        private void AddErrorMessage(DMClass dmClass, DBPrimaryKeyColumn pkColumn, IList<string> errorMessages)
        {
            string errorMessage = string.Format("The primary key for business object '{0}' could not be "
                                                + "created since the column '{1}' do not exist on the business object"
                                                , dmClass.ClassNameBO, pkColumn.ColumnName);
            errorMessages.Add(errorMessage);
        }

        private IBusinessObject[] GetBusinessObjectArray(IBusinessObjectCollection fromBOCol)
        {
            IBusinessObject[] businessObjects = new IBusinessObject[fromBOCol.Count];
            fromBOCol.CopyTo(businessObjects, 0);
            return businessObjects;
        }
        private bool ApprovedDelete(IMergableBo pkColumn)
        {
            return pkColumn.PendingChangeType == ChangeType.Delete && pkColumn.PendingChangeApproved;
        }

        private Predicate<DBPrimaryKeyColumn> MatchColumn(DMProperty dmProperty)
        {
            return column => 
                   column.Column.ColumnName == dmProperty.MappedDBColumnName;
        }

        private DMObjectIdentity GetMappedObjectIdentity(DMClass dmClass, DBPrimaryKey dbPrimaryKey)
        {
            DMObjectIdentity objectIdentity = dbPrimaryKey.GetMappedDMObjectIdentity();
            if (objectIdentity != null && objectIdentity.Class != dmClass)
            {
                objectIdentity.MappedDBPrimaryKey = null;// objectIdentity.Class.MappedTable.PrimaryKeyDB;
                objectIdentity = null;
            }
            if (objectIdentity == null)
            {
                objectIdentity = dmClass.GetObjectID() ?? new DMObjectIdentity { Class = dmClass };
            }
            objectIdentity.MappedDBPrimaryKey = dbPrimaryKey;
            return objectIdentity;
        }
    }
}